#ifndef XG_MEMQUEUE_CPP
#define XG_MEMQUEUE_CPP
////////////////////////////////////////////////////////
#include "../File.h"
#include "../MemQueue.h"

#ifndef XG_MSGQUEUE_SEMNAME_HEAD
#define XG_MSGQUEUE_SEMNAME_HEAD	"Global\\SEMAPHORE"
#endif

SmartBuffer MemQueue::pop()
{
	u_int32 len;
	SmartBuffer buffer;
	u_char* data = pop(len);

	if (data == NULL) return buffer;

	memcpy(buffer.malloc(len), data, len);

	return buffer;
}
u_char* MemQueue::pop(u_int32& len)
{
	if (head->len == 0)
	{
		len = 0;

		return NULL;
	}

	Node* node = front();

	head->str += node->memsize();

	if (head->str == head->bottom)
	{
		head->bottom = head->tail;
		head->str = 0;
	}

	if (head->len-- == 1) head->str = head->end = 0;

	len = node->size;

	return node->data;
}
bool MemQueue::push(const void* data, u_int32 len)
{
	if (len <= 0) return false;

	u_int32 size = sizeof(u_int32) + len;

	if (head->str <= head->end)
	{
		if (head->end + size >= head->tail)
		{
			if (head->str == 0 || size >= head->str) return false;

			head->bottom = head->end;
			head->end = 0;
		}
	}
	else
	{
		if (head->end + size >= head->str) return false;
	}

	Node* node = back();

	head->len++;
	node->init(data, len);
	head->end = node->offset(head) + node->memsize();

	return true;
}
bool MemQueue::create(void* buffer, u_int32 maxsz)
{
	if (maxsz <= sizeof(Head)) return false;

	maxsz -= sizeof(Head);
	head = (Head*)(buffer);
	head->tail = maxsz;
	clear();

	return true;
}

MsgQueue::~MsgQueue()
{
	close();
}
void MsgQueue::close()
{
	if (sem.canUse())
	{
		sem.wait();
		sem.release();
		sem.close();
	}

	shm.close();
}
bool MsgQueue::clear()
{
	CHECK_FALSE_RETURN(canUse());
	CHECK_FALSE_RETURN(sem.wait());

	mq.clear();
	sem.release();

	return true;
}
bool MsgQueue::open(const string& name)
{
	close();

	if (sem.open(XG_MSGQUEUE_SEMNAME_HEAD + name) && shm.open(name))
	{
		if (sem.wait())
		{
			if (mq.open(shm.get()))
			{
				this->name = name;

				sem.release();

				return true;
			}

			sem.release();
		}
	}

	close();

	return false;
}
bool MsgQueue::create(const string& name, u_int32 len)
{
	close();

	if (sem.create(XG_MSGQUEUE_SEMNAME_HEAD + name) && sem.release() && shm.create(name, len))
	{
		len = shm.size();

		if (len <= 0)
		{
			sem.close();
			shm.close();

			return false;
		}

		if (sem.wait())
		{
			if (mq.create(shm.get(), len))
			{
				this->name = name;

				sem.release();

				return true;
			}

			sem.release();
		}
	}

	close();

	return false;
}
bool MsgQueue::push(SmartBuffer data)
{
	return push(data.str(), data.size());
}
bool MsgQueue::push(const void* data, u_int32 len)
{
	CHECK_FALSE_RETURN(canUse());
	CHECK_FALSE_RETURN(sem.wait());

	bool res = mq.push(data, len);

	sem.release();

	return res;
}
bool MsgQueue::pop(void* data, u_int32& len)
{
	CHECK_FALSE_RETURN(canUse());
	CHECK_FALSE_RETURN(sem.wait());

	u_int32 val;
	u_char* tmp = mq.pop(val);

	if (tmp && len >= val)
	{
		memcpy(data, tmp, val);
		sem.release();
		len = val;

		return true;
	}

	sem.release();

	return false;
}
SmartBuffer MsgQueue::pop()
{
	SmartBuffer data;

	if (canUse())
	{
		if (sem.wait())
		{
			data = mq.pop();

			sem.release();
		}
	}

	return data;
}
bool MsgQueue::pop(SmartBuffer& data, u_int32& len)
{
	CHECK_FALSE_RETURN(canUse());
	CHECK_FALSE_RETURN(sem.wait());

	u_char* ptr = mq.pop(len);

	if (ptr) memcpy(data.truncate(len), ptr, len);

	sem.release();

	return len > 0;
}
////////////////////////////////////////////////////////
#endif